/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.context;

import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.context.core.Context;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.model.results.R1;
import org.zhiqim.kernel.util.Strings;

/**
 * HttpContext引导类，为初始化类，允许子类实现，每context根据自身要求初始化和释放对象
 * 
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class ZmlBootstrap
{
    protected static Log log = LogFactory.getLog(ZmlBootstrap.class);
    protected ZmlContext context;
    
    private boolean isBefore;
    private boolean isAfter;
    private volatile boolean isClosed;
    
    /** 设置上下文环境 */
    public final void setContext(ZmlContext context)
    {
        if (this.context != null)
            return;
        
        this.context = context;
    }
    
    /** 获取上下文环境 */
    public final Context getContext()
    {
        return context;
    }
    
    /***************************************************************************/
    //解决多依赖关系下一个组件的引导类只能引导一次
    /***************************************************************************/
    
    /** 是否已前部引导 */
    public final boolean isBefore()
    {
        return isBefore;
    }

    /** 设置是否前部引导 */
    public final void setBefored()
    {
        this.isBefore = true;
    }
    
    /** 是否已后部引导 */
    public final boolean isAfter()
    {
        return isAfter;
    }

    /** 设置是否已后部引导 */
    public final void setAftered()
    {
        this.isAfter = true;
    }

    /** 是否已销毁 */
    public final boolean isClosed()
    {
        return isClosed;
    }
    
    /** 关闭引导，子类实现释放资源接口 */
    public final void close()
    {
        if (!isClosed)
            return;
        
        isClosed = true;
        try{destroy();}catch(Throwable e){}
    }
    
    /***************************************************************************/
    //子类可重写的三个受保护方法
    /***************************************************************************/
    
    /** 在配置加载之后,在ZML配置之前 */
    protected void initBefore() throws Exception
    {
    }
    
    /** 在配置加载之后,在ZML配置之后 */
    protected void initAfter() throws Exception
    {
    }

    /** 释放资源接口，注:如果在init方法内初始化了线程等应用,务必在这里释放 */
    protected void destroy()
    {
    }
    
    /***************************************************************************/
    //子类可重写的调用和两个日志的公开方法
    /***************************************************************************/
    
    /**
     * 事件（如组件中通知宿主工程，通过type区分事件类型）
     * 
     * @param request   请求
     * @param type      事件类型
     * @param values    事件值数组
     */
    public R1 event(HttpRequest request, int type, Object... values)
    {
        return R1.correct();
    }
    
    /**
     * 日志输出接口
     * 
     * @param request   请求
     * @param message   消息
     */
    public void log(HttpRequest request, String message)
    {
        log(request, message, null);
    }
    
    /**
     * 日志输出接口
     * 
     * @param request   请求
     * @param message   消息
     * @param e         访问时产生的异常
     */
    public void log(HttpRequest request, String message, Throwable e)
    {
        String sessionName = Strings.toString(request.getSessionName(), Strings.toString(request.getRequestName(), "guest"));
        StringBuilder strb = new StringBuilder()
            .append("USER:").append(sessionName).append(" ")
            .append("IP:").append(request.getRemoteAddr()).append(" ")
            .append("URI:").append(request.getRequestURI());
        
        if (message != null)
            strb.append(" ").append(message);
            
        if (e == null)
            log.info(strb.toString());
        else
            log.error(strb.toString(), e);
    }
}
